<template>
  <div class="plum-cpt-wrap">
    <canvas
      v-show="showPlum"
      ref="Plum"
      @click="refresh()"
    />
  </div>
</template>

<script lang="ts" setup>
import { computed, onMounted, watch, ref } from 'vue'
import { appStore } from '@/store/app'
const store = appStore()

const Plum:any = ref(null)

const width:any = ref(600)
const height:any = ref(600)
const ctx:any = ref(null)
const branchLength = ref(6) // 左右分支长度
const branchRandom = ref(0.5) // 左右分支的概率范围，0-1，值越大每次产生分支的概率就越大
const queue:any = ref([])
const initDepth = ref(4)
const r90 = ref(Math.PI / 2)
const r180 = ref(Math.PI)
const strokeColor = ref('#ffc0cb80')
const depth = ref(0)
const stopped = ref(false)
const interval = ref(1000 / 40)
const lastTime = ref(0)
const duration = ref(5000)// 特效持续时间

const showPlum = computed(() => {
  return store.showPlum
})

watch(() => showPlum, (newVal, oldVal) => {
  if (newVal) {
    refresh()
  } else {
    depth.value = 0
    queue.value.splice(0)
  }
})

onMounted(async () => {
  width.value = window.innerWidth
  height.value = window.innerHeight
  Plum.value.style.width = width.value + 'px'
  Plum.value.style.height = height.value + 'px'
  Plum.value.width = width.value
  Plum.value.height = height.value
  const canvas = Plum.value
  ctx.value = canvas.getContext('2d')
  if (showPlum.value) {
    handleStep()
    handleFrame()
    setTimeout(() => {
      queue.value.splice(0)
    }, duration.value)
  }
})

const refresh = () => {
  ctx.value.clearRect(0, 0, width.value, height.value)
  depth.value = 0
  handleStep()
  handleFrame()
  setTimeout(() => {
    queue.value.splice(0)
  }, duration.value)
}
const handleStep = () => {
  queue.value.push(
    () => step(Math.random() * width.value, height.value, -r90.value), // 下边的梅花
    () => step(Math.random() * width.value, 0, r90.value), // 上边的梅花
    () => step(0, Math.random() * height.value, 0), // 左边的梅花
    () => step(width.value, Math.random() * height.value, -r180.value) // 右边的梅花
  )
  if (width.value < 500) {
    duration.value = 4500
    queue.value = queue.value.slice(0, 2)
  }
}
// const getEndPoin = (x: number, y: number, angle: number) => {
//   const length = branchLength.value
//   const y1 = length * Math.sin(angle) // 对边
//   const x1 = length * Math.cos(angle) // 邻边
//   return {
//     x: x + x1,
//     y: y + y1
//   }
// }
const drawBranch = (startX: any, startY: any, end: any) => {
  drawLine({ x: startX, y: startY }, end)
}

const step = (x: number, y: number, angle: number) => {
  if (x < -50 || x > width.value + 50 || y < -50 || y > height.value + 50) {
    // 超出屏幕一定范围就return
    return
  }

  const getEndPoin1 = (x: number, y: number, angle: number) => {
    // const length = branchLength.value
    const length = Math.random() * branchLength.value
    // const length =
    //   branchLength.value +
    //   (Math.random() > 0.2 ? +Math.random() * 2 : -Math.random() * 2)
    const x1 = length * Math.cos(angle) // 邻边
    const y1 = length * Math.sin(angle) // 对边
    return {
      x: x + x1,
      y: y + y1
    }
  }
  const end = getEndPoin1(x, y, angle)
  drawBranch(x, y, end)
  const rad1 = angle + Math.random() * (r180.value / 12)
  const rad2 = angle - Math.random() * (r180.value / 12)

  if (depth.value <= initDepth.value || Math.random() > branchRandom.value) {
    queue.value.push(() => step(end.x, end.y, rad1))
  }
  if (depth.value <= initDepth.value || Math.random() > branchRandom.value) {
    queue.value.push(() => step(end.x, end.y, rad2))
  }
}
const frame = () => {
  stopped.value = false
  if (performance.now() - lastTime.value < interval.value) {
    return
  }
  const tasks = [...queue.value]
  queue.value.splice(0)
  depth.value += 1

  lastTime.value = performance.now()
  if (!tasks.length) {
    stopped.value = true
    return
  }
  tasks.forEach((fn) => {
    fn()
  })
}
const handleFrame = () => {
  requestAnimationFrame(() => {
    frame()
    // handleFrame()
    !queue.value.length && (stopped.value = true)
    queue.value.length && handleFrame()
  })
}

const drawLine = (startPoin: { x: any; y: any }, endPoin: { x: any; y: any }) => {
  // 这是一段使用 lineTo 方法的简单的代码片段。 使用 beginPath() 绘制路径的起始点， 使用 moveTo()移动画笔， 使用 stroke() 方法真正地画线。
  ctx.value.strokeStyle = strokeColor.value
  ctx.value.beginPath()
  ctx.value.moveTo(startPoin.x, startPoin.y)
  ctx.value.lineTo(endPoin.x, endPoin.y)
  ctx.value.stroke()
}
</script>

<style scoped>
.plum-cpt-wrap {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 101;
  pointer-events: none;
}
</style>
